/*
 * Copyright 2007. Mount Sinai Hospital, Toronto, Canada.
 * 
 * Licensed under the GNU Lesser General Public License, Version 2. You
 * can find a copy of the license at:
 * 
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
 * 
 * IN NO EVENT SHALL MOUNT SINAI HOSPITAL BE LIABLE TO ANY PARTY FOR DIRECT, 
 * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST 
 * PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, 
 * EVEN IF MOUNT SINAI HOSPITAL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 
 * DAMAGE.
 * 
 * MOUNT SINAI HOSPITAL SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND 
 * ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". 
 * MOUNT SINAI HOSPITAL HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, 
 * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 
 */
package com.sinai.mshab.client.ui.basic;

import java.util.Iterator;

import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.KeyboardListener;
import com.google.gwt.user.client.ui.KeyboardListenerAdapter;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.Widget;
import com.sinai.mshab.client.util.Answer;
import com.sinai.mshab.client.ui.aggregate.DataReceiver;
import com.sinai.mshab.client.ui.aggregate.FormData;

/**
 * Very similar to text question component, only difference is that the text you
 * type cannot be seen and is displayed as ******
 * 
 * @author serge
 * 
 */
public class PasswordComponent extends QuestionComponent {
	private int width = 200;

	/**
	 * Creates a new TextQuestionComponent.
	 * 
	 * @param dbfieldName
	 *            the name of the field to which the PasswordTextBox information
	 *            corresponds to.
	 * @param tableName
	 *            the name of the database table where the PasswordTextBox
	 *            information will be stored.
	 * @param description
	 *            The description label that goes before PasswordTextBox (eg.
	 *            Name)
	 */
	public PasswordComponent(String dbfieldName, String tableName,
			String description) {
		initializeWidget(dbfieldName, tableName, description, "", "");
	}

	/**
	 * Creates a new TextQuestionComponent.
	 * 
	 * @param dbfieldName
	 *            the name of the field to which the PasswordTextBox information
	 *            corresponds to.
	 * @param tableName
	 *            the name of the database table where the PasswordTextBox
	 *            information will be stored.
	 * @param description
	 *            The description label that goes before PasswordTextBox (eg.
	 *            Name)
	 * @param quantifier
	 *            The quantifier label that goes after PasswordTextBox (eg.
	 *            /years)
	 */
	public PasswordComponent(String dbfieldName, String tableName,
			String description, String quantifier) {
		initializeWidget(dbfieldName, tableName, description, quantifier, "");
	}

	/**
	 * Creates a new TextQuestionComponent.
	 * 
	 * @param dbfieldName
	 *            the name of the field to which the PasswordTextBox information
	 *            corresponds to.
	 * @param tableName
	 *            the name of the database table where the PasswordTextBox
	 *            information will be stored.
	 * @param description
	 *            The description label that goes before PasswordTextBox (eg.
	 *            Name)
	 * @param quantifier
	 *            The quantifier label that goes after PasswordTextBox (eg.
	 *            /years)
	 * @param error_msg
	 *            The error message that gets displayed if the attached
	 *            validators do not pass
	 */
	public PasswordComponent(String dbfieldName, String tableName,
			String description, String quantifier, String error_msg) {
		initializeWidget(dbfieldName, tableName, description, quantifier,
				error_msg);
	}

	/**
	 * Helper method in creating a new <code>TextComponent</code>. This
	 * allows for us to have one central method for creating a
	 * <code>TextComponent</code> even though we take in a different number of
	 * parameters.
	 * 
	 * @param dbfieldName
	 *            the name of the field to which the PasswordTextBox information
	 *            corresponds to.
	 * @param tableName
	 *            the name of the database table where the PasswordTextBox
	 *            information will be stored.
	 * @param description
	 *            The description label that goes before PasswordTextBox (eg.
	 *            Name)
	 * @param quantifier
	 *            The quantifier label that goes after PasswordTextBox (eg.
	 *            /years)
	 * @param error_msg
	 *            The error message that gets displayed if the attached
	 *            validators do not pass
	 */
	private void initializeWidget(String dbfieldName, String tableName,
			String description, String quantifier, String error_msg) {

		this.dbfieldName = dbfieldName;
		this.tableName = tableName;
		this.description = description;
		this.quantifier = quantifier;
		this.error_msg = error_msg;

		// all our widgets go to the horizontal panel
		HorizontalPanel panel;
		description_label = new Label(description);
		widget = new PasswordTextBox();
		quantifier_label = new Label(quantifier);
		error_label = new Label(error_msg);

		// adding custom style names for CSS to give custom rendering to these
		// components
		description_label.setStyleName("description_label");
		quantifier_label.setStyleName("quantifier_label");
		error_label.setStyleName("error_label");

		// need a keyboard listener
		((PasswordTextBox) widget)
				.addKeyboardListener(new ValidationKeyboardListener());
		((PasswordTextBox) widget).addFocusListener(this);

		// panel containing other widgets
		panel = new HorizontalPanel();
		panel.add(description_label);
		panel.add(widget);
		panel.add(quantifier_label);
		panel.add(error_label);

		// no error at creation time, so error label not visible.
		error_label.setVisible(false);

		// set the proper alt
		widget.setTitle(description);
		widget.setWidth(width + "px");

		// starting the panel.
		initWidget(panel);
	}

	public void sendAnswer(DataReceiver receiver) {
		receiver.sendData(getAnswer());
	}

	public Answer getAnswer() {
		Answer answer = new Answer();
		answer
				.add(tableName, dbfieldName, ((PasswordTextBox) widget)
						.getText());
		answer.add(hiddenFields);
		return answer;
	}

	/**
	 * When to focus is lost validate the field.
	 */
	public void onLostFocus(Widget sender) {
		String name = ((PasswordTextBox) widget).getStyleName();
		if (name.indexOf("_focus") != -1) {
			((PasswordTextBox) widget).setStyleName(name.substring(0, name
					.length()
					- "_focus".length()));
		}
		validate();
	}

	/**
	 * When to focus is lost validate the field.
	 */
	public void onFocus(Widget sender) {
		String name = ((PasswordTextBox) widget).getStyleName();
		((PasswordTextBox) widget).setStyleName(name + "_focus");
	}

	/**
	 * Sets the text of the PasswordTextBox to 'message'
	 * 
	 * @param message
	 *            The text that will go to the text field.
	 */
	public void setText(String message) {
		((PasswordTextBox) widget).setText(message);
	}

	/**
	 * Returns the text of the PasswordTextBox.
	 * 
	 * @param message
	 *            The text that is in the PasswordTextBox
	 */
	public String getText() {
		return ((PasswordTextBox) widget).getText();
	}

	/**
	 * The keyboard listener will call the validate method upon every key
	 * entered when the error state is on.
	 * 
	 * @author serge
	 */
	private class ValidationKeyboardListener extends KeyboardListenerAdapter {
		public void onKeyUp(Widget sender, char keyCode, int modifiers) {

			// this code extends the text box to accomodate more text being
			// written by the user. it extends only to a certain point.
			PasswordTextBox tb = (PasswordTextBox) widget;
			int len = tb.getText().length();

			if (len > 25) {
				int increment = Math.min((len - 20), 40);
				tb.setWidth((width + increment * 8) + "px");
			} else {
				tb.setWidth(width + "px");
			}

			// check if validation should be done
			// validate();

			// apply mask if it exists
			if (mask != null) {
				setText(mask.applyMask(getText()));
			}

			// notify of change
			notifyObservers(PasswordComponent.this);
		}
	}

	public Object clone() {
		BasicFormComponent t;
		t = new TextQuestionComponent(dbfieldName, tableName, description,
				quantifier, error_msg);

		t.setMask(this.mask);
		t.setValidator(this.validator);

		if (subquestion)
			t.setAsSubQuestion();

		return t;
	}

	/**
	 * Populate this widget with FormData using an Answer object
	 * 
	 * @param answer
	 *            the answer object containing the data.
	 */
	public boolean populate(Answer answer) {

		// if answer is null, do nothing
		if (answer == null) {
			return false;
		}

		// walking through all the fields-values of answer
		Iterator field_names = answer.getHashMap().keySet().iterator();
		while (field_names.hasNext()) {
			String field_name = (String) field_names.next();

			// if field name matches our widget's field name, use this value
			if (field_name.equalsIgnoreCase(dbfieldName)) {
				String value = (String) answer.getHashMap().get(field_name);
				((PasswordTextBox) widget).setText(value);

				// apply mask if it exists
				if (mask != null) {
					setText(mask.applyMask(getText()));
				}

				// if we populaeted the widget with nothing, return false.
				if (value == null || value.length() == 0) {
					return false;
				}

				return true;
			}
		}
		return false;
	}

	public void setEnabled(boolean value) {
		((PasswordTextBox) widget).setEnabled(value);
	}

	/**
	 * Populate this widget with FormData
	 */
	public boolean populate() {
		Answer a = FormData.getData(tableName);
		return populate(a);
	}

	/**
	 * Set's the textbox's css style.
	 * 
	 * @param style
	 *            the new css style name
	 */
	public void setInnerStyleName(String style) {
		((PasswordTextBox) widget).setStyleName(style);
	}

	/**
	 * Set's the description's label css style.
	 * 
	 * @param style
	 *            the new css style name
	 */
	public void setDescriptionStyleName(String style) {
		this.description_label.setStyleName(style);
	}

	/**
	 * Adds a keyboard listener to the password box.
	 * 
	 * @param listener
	 */
	public void addKeyboardListener(KeyboardListener listener) {
		((PasswordTextBox) widget).addKeyboardListener(listener);
	}
}
